`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2022/05/12 21:08:42
// Design Name: 
// Module Name: ahb_slave
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module ahb_slave
#(parameter N=1024,
  parameter ID=0)
(
input logic HCLK,
input logic HRESETn,
input logic [31:0] HADDR,
input logic [1:0] HTRANS,
input logic HWRITE,
input logic [2:0] HSIZE,
input logic [2:0] HBURST,
input logic [3:0] HPROT,
input logic [31:0] HWDATA,
output logic [31:0] HRDATA,
output logic HREADY,
output logic [1:0] HRESP,
input logic HSEL
    );
logic [31:0] RAM [0:N-1];
logic [31:0] addr_r;               //寄存的地址信号
logic flag;                        //寄存的读写信号
//HTRANS四种取值
parameter SEQ=2'b11;
parameter NOSEQ=2'b10;
parameter BUSY=2'b01;
parameter IDLE=2'b00;
//state machine
typedef enum bit [1:0]{
   WAIT,
   READ,
   WRITE
}State;
State cur_state,next_state;
//fsm 1
always_ff@(posedge HCLK,negedge HRESETn)
if(~HRESETn)
    cur_state<=WAIT;
else
    cur_state<=next_state;
//fsm_2
always_comb
if(HSEL==1'b1)
case(cur_state)
    WAIT:if(HTRANS==NOSEQ||HTRANS==SEQ)
	        if(HWRITE==1)
			    next_state=WRITE;
			else
			    next_state=READ;
	READ:if(HREADY)
	         if(HTRANS==NOSEQ||HTRANS==SEQ)
			    if(HWRITE)
				    next_state=WRITE;
				else
				    next_state=READ;
			 else
			    next_state=WAIT;
		else
		    next_state=READ;
	WRITE:if(HREADY)
	          if(HTRANS==NOSEQ||HTRANS==SEQ)
			     if(HWRITE)
				    next_state=WRITE;
				 else
				    next_state=READ;
			  else
			     next_state=WAIT;
		   else
		       next_state=WRITE;
	default:next_state=WAIT;
endcase
else
    next_state=WAIT;
//addr_r
always_ff@(posedge HCLK,negedge HRESETn)
if(~HRESETn)
   addr_r<=0;
else if(HSEL)
begin
    if(cur_state==WAIT&&(HTRANS==SEQ||HTRANS==NOSEQ))              //相当于valid信号
       addr_r<=HADDR;
    else if((cur_state==READ||cur_state==WRITE)&&HREADY&&(HTRANS==NOSEQ||HTRANS==SEQ))
       addr_r<=HADDR;
end
//flag
always_ff@(posedge HCLK,negedge HRESETn)
if(~HRESETn)
   flag<=0;
else if(HSEL)
begin
    if(cur_state==WAIT&&(HTRANS==SEQ||HTRANS==NOSEQ))
       flag<=HWRITE;
    else if((cur_state==READ||cur_state==WRITE)&&HREADY&&(HTRANS==NOSEQ||HTRANS==SEQ))
       flag<=HWRITE;
end
//read data
always_comb
if(HREADY)
    HRDATA=RAM[addr_r[31:2]];
else
    HREADY=0;
//write data
always_ff@(posedge HCLK)
if(HREADY&&flag)
begin
    RAM[addr_r[31:2]]<=HWDATA;
	$display("ID=%d,write %d to %d",ID,HWDATA,addr_r);
end
//HREADY
always_ff@(posedge HCLK,negedge HRESETn)
if(~HRESETn)
    HREADY<=0;
else if(HSEL)
begin
    if(~HREADY&&(cur_state==READ||cur_state==WRITE))                   //
    begin
        HREADY<=1;
    end
    else if(HREADY&&(cur_state==READ||cur_state==WRITE))
        HREADY<=0;
end
//HRESP
assign HRESP=2'b00;
//初始化RAM
initial
begin
   for(int i=0;i<N;i++)
       RAM[i]=i+ID;
end
endmodule
